# -*- coding: utf-8 -*-
# @Author  : CaoHan
# @Time    : 2023/11/9 16:22
import math
from ds.enumClass import ContainerState
from ds.container import AppFlops

uavId = 0
FLOPS = 251.7
MEM = 384  # GB
BatteryJ = 288000
P_idle = 51
P_max = 231
P_mid = 55  # (P_max-P_idle)/(P_mid-P_idle)=45
cs_factor = 0.8


class UAV:
    def __init__(self, x, y):
        global uavId
        self.id = uavId
        uavId += 1
        self.x = x
        self.y = y
        self.v = 0
        self.d = 0
        # 一个UAV携带一台主机
        self.isOn = True
        self.remainFLOPS = FLOPS
        self.remainMem = MEM
        self.remainEnergy = BatteryJ
        self.containerIdList = []
        self.spareConIdList = []  # 空闲的容器id
        self.lastComputeEnergy = 0
        self.lastFlightEnergy = 0
        self.lastHarvestTime = 0
        # 通信:发射功率和时间
        self.transP = 2
        # 拒绝次数
        self.rejectNum = 0
        # 是否可以被卸载
        self.beOffloaded = True
        # 总共消耗的能量
        self.consumeE = 0
        # 总共关闭的时间
        self.closeTime = 0
        # 上一次关机的时间点
        self.lastCloseT = -1

    def updateEnergy(self, time, containerList, interp_func):
        # self.updateFlightEnergy(time)
        self.updateHarvestEnergy(time, interp_func)
        self.updateComputeEnergy(time, containerList)
        if self.remainEnergy >= BatteryJ:
            self.remainEnergy = BatteryJ
        if self.isOn:
            if self.remainEnergy < 0:
                self.remainEnergy = 0
                self.isOn = False
                self.remainFLOPS = FLOPS
                self.remainMem = MEM
                self.lastCloseT = time
                # 对所有容器关闭
                for c_id in self.containerIdList:
                    container = containerList[c_id]
                    if container.state == ContainerState.COLD_START:
                        container.csTime[-1].end = time
                    elif container.state == ContainerState.RUN:
                        container.runTime[-1].end = time
                    container.state = ContainerState.KILL
                    container.killedTime = time
                self.containerIdList = []
                self.spareConIdList = []
                self.beOffloaded = False
        else:  # 已经关机
            if self.remainEnergy > 0:  # 开机
                self.isOn = True
                self.beOffloaded = True
                self.closeTime += time - self.lastCloseT

    def updateFlightEnergy(self, time):
        P = 158.76 + 88.63  # 悬停功耗
        # v >> 4.03
        # return 158.76 * (1 + 3 * self.v ** 2 / 120 ** 2) + 88.63 * 4.03 / self.v + 0.00462131 * self.v ** 3
        self.remainEnergy -= P * time - self.lastFlightEnergy
        self.lastFlightEnergy = P * time

    def updateHarvestEnergy(self, time, interp_func):
        P = interp_func(time + 9 * 3600)  # 实验从9点开始
        harvestE = P * (time - self.lastHarvestTime)
        self.remainEnergy += harvestE
        self.lastHarvestTime = time

    def updateComputeEnergy(self, time, containerList):
        cpu_i = []
        t_i_cs = []
        t_i_run = []
        t_i_total = []
        containerUavList = []
        for c in containerList:
            if c.uavId == self.id:
                containerUavList.append(c)
        for container in containerUavList:
            cpu_i.append(container.flops)
            t_cs = 0
            for slot in container.csTime:
                if slot.end == -1:
                    t_cs += time - slot.start
                else:
                    t_cs += slot.end - slot.start
            t_i_cs.append(t_cs)

            t_run = 0
            for slot in container.runTime:
                if slot.end == -1:
                    t_run += time - slot.start
                else:
                    t_run += slot.end - slot.start
            t_i_run.append(t_run)
            if container.state == ContainerState.KILL:
                t_total = container.killedTime - container.createTime
            else:
                t_total = time - container.createTime
            t_i_total.append(t_total)

        sum_cs, sum_running, sum_total = 0, 0, 0
        for i in range(len(cpu_i)):
            sum_cs += cpu_i[i] * t_i_cs[i]
            sum_running += cpu_i[i] * t_i_run[i]
            sum_total += cpu_i[i] * t_i_total[i]
        t_pm = time - self.closeTime  # 假设无人机的主机从0开到time,减去closeTime
        if self.isOn:
            # 累计消耗的能量
            total_compute_energy = P_idle * t_pm + (P_max - P_mid) * sum_running / FLOPS + cs_factor * (
                    P_max - P_mid) * sum_cs / FLOPS + (P_mid - P_idle) * sum_total / FLOPS
            # 这段时间消耗的能量
            consumeEnergy = total_compute_energy - self.lastComputeEnergy
            # 更新
            self.remainEnergy -= consumeEnergy
            self.lastComputeEnergy = total_compute_energy
            self.consumeE += consumeEnergy

    def getColdStartE(self):
        return cs_factor * (P_max - P_mid) * 10 * (AppFlops / FLOPS)

    def transT_E(self, task_size, distance):
        R = 4 * 10 ** 7 * math.log2(1 + self.transP * 10 ** 6 / distance ** 2)
        R = R / 8000000  # 换算成MB
        t = task_size / R
        E = self.transP * t
        self.remainEnergy -= E
        return t

    def transTwithoutE(self, task_size, distance):
        # 不真正发射
        R = 4 * 10 ** 7 * math.log2(1 + self.transP * 10 ** 6 / distance ** 2)
        R = R / 8000000  # 换算成MB
        t = task_size / R
        E = self.transP * t
        # print("task_size = " + str(task_size) + "; E = " + str(E) + "; t = " + str(t))
        return t, E
